﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
using System.Runtime.InteropServices;
using System.IO;
/*
Copyright 2010 Mirosław M. Mączka

This file is part of Flac2Wma.

    Flac2Wma is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/
namespace Flac2Wma
{
    class Handler_Flac
    {
                //
        //
        public string FileFlacPathName { get; set; }
        public string FileWavPathName { get; set; }
        //
        //
        public long flacFileLength = 0;
        public long wavFileLength = 0;
        //
        /// <summary>
        /// Error message from exception
        /// </summary>
        public string ErrorMessage { get; set; }
        private static string staticErrorMessage { get; set; }
        //
        /// <summary>
        /// Flac file in invalid format (must be 16bit stereo)
        /// </summary>
        public bool InvalidFormat { get; set; }
        //
        public int PlayTime { get; set; }
        //
        // ////////////////////////////////////////////////////////////////////////////////////////////////////////
        //168 The variable *** is declared but never used
        //169 The field *** is declared but never used
        //649 is never assigned to, and will always have its default value 0

#pragma warning disable 168, 169, 649
        //
        public enum FLAC__StreamDecoderWriteStatus
        {
            FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
            FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
        };
        //
        //#define FLAC__MAX_CHANNELS (8u)
        //#define FLAC__MAX_FIXED_ORDER (4u)
        //#define FLAC__MAX_LPC_ORDER (32u) 

        const uint FLAC__MAX_CHANNELS = 8;
        const uint FLAC__MAX_FIXED_ORDER = 4;
        const uint FLAC__MAX_LPC_ORDER = 32;

        public enum FLAC__StreamDecoderInitStatus
        {
            FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
            //< Initialization was successful.
            FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
            //< The library was not compiled with support for the given container format.
            FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
            //< A required callback was not supplied.
            FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
            //< An error occurred allocating memory.
            FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
            //< fopen() failed in FLAC__stream_decoder_init_file() or FLAC__stream_decoder_init_ogg_file().
            FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
            //< FLAC__stream_decoder_init_*() was called when the decoder was  already initialized, usually because FLAC__stream_decoder_finish() was not called.
        }

        public enum FLAC__MetadataType
        {
            FLAC__METADATA_TYPE_STREAMINFO = 0,
            //< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block
            FLAC__METADATA_TYPE_PADDING = 1,
            //< <A HREF="../format.html#metadata_block_padding">PADDING</A> block
            FLAC__METADATA_TYPE_APPLICATION = 2,
            //< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block
            FLAC__METADATA_TYPE_SEEKTABLE = 3,
            //< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block
            FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
            //< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags)
            FLAC__METADATA_TYPE_CUESHEET = 5,
            //< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block
            FLAC__METADATA_TYPE_PICTURE = 6,
            //< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block
            FLAC__METADATA_TYPE_UNDEFINED = 7
            //< marker to denote beginning of undefined type range; this number will increase as new metadata types are added
        }

        public enum FLAC__ChannelAssignment
        {
            FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, //< independent channels
            FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, //< left+side stereo
            FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, //< right+side stereo
            FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 //< mid+side stereo
        }
        public enum FLAC__FrameNumberType
        {
            FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, //< number contains the frame number
            FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER //< number contains the sample number of first sample in frame
        }
        public enum FLAC__SubframeType
        {
            FLAC__SUBFRAME_TYPE_CONSTANT = 0, //< constant signal
            FLAC__SUBFRAME_TYPE_VERBATIM = 1, //< uncompressed signal
            FLAC__SUBFRAME_TYPE_FIXED = 2, //< fixed polynomial prediction
            FLAC__SUBFRAME_TYPE_LPC = 3 //< linear prediction
        }
        public enum FLAC__EntropyCodingMethodType
        {
            FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0,
            //< Residual is coded by partitioning into contexts, each with it's own 4-bit Rice parameter.
            FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1
            //< Residual is coded by partitioning into contexts, each with it's own 5-bit Rice parameter.
        }

        public enum FLAC__StreamDecoderErrorStatus
        {
            FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
            //< An error in the stream caused the decoder to lose synchronization. */
            FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
            //< The decoder encountered a corrupted frame header. */
            FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
            //< The frame's data did not match the CRC in the footer. */
            FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
            //< The decoder encountered reserved fields in use in the stream. */
        }
        //=======================================================================================
        //
        [StructLayout(LayoutKind.Explicit)]
        public struct FLAC__FrameHeader
        {
            [FieldOffset(0)]
            public uint blocksize;//unsigned
            //< The number of samples per subframe.
            [FieldOffset(4)]
            public uint sample_rate;//unsigned
            //< The sample rate in Hz.
            [FieldOffset(8)]
            public uint channels;//unsigned
            //< The number of channels (== number of subframes).
            [FieldOffset(12)]
            public FLAC__ChannelAssignment channel_assignment;
            //< The channel assignment for the frame.
            [FieldOffset(16)]
            public uint bits_per_sample;//unsigned
            //< The sample resolution.
            [FieldOffset(20)]
            public FLAC__FrameNumberType number_type;
            //< The numbering scheme used for the frame.  As a convenience, the
            // decoder will always convert a frame number to a sample number because
            // the rules are complex.
            //union {
            [FieldOffset(24)]
            public UInt32 frame_number;// typedef unsigned __int32 FLAC__uint32;
            [FieldOffset(24)]
            public UInt64 sample_number;//typedef unsigned __int64 FLAC__uint64;
            //};
            //< The frame number or sample number of first sample in frame;
            // use the \a number_type value to determine which to use.
            [FieldOffset(28)]
            public byte crc;//typedef unsigned char FLAC__uint8;
            //< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
            // of the raw frame header bytes, meaning everything before the CRC byte
            // including the sync code.
        }
        public struct FLAC__Subframe_Constant
        {
            public Int32 value; //< The constant signal value. (FLAC__int32)
        }
        public struct FLAC__Subframe_Verbatim
        {
            public IntPtr data; //< A pointer to verbatim signal. (const FLAC__int32*)
        }

        public struct FLAC__EntropyCodingMethod_PartitionedRiceContents
        {
            //unsigned *parameters;
            public IntPtr parameters;
            //< The Rice parameters for each context.
            //unsigned *raw_bits;
            public IntPtr raw_bitst;
            //< Widths for escape-coded partitions.  Will be non-zero for escaped partitions and zero for unescaped partitions.
            //unsigned capacity_by_order;
            public uint capacity_by_order;
            //< The capacity of the \a parameters and \a raw_bits arrays specified as an order, i.e. the number of array elements allocated is 2 ^ \a capacity_by_order.
        }

        public struct FLAC__EntropyCodingMethod_PartitionedRice
        {
            uint order;// unsigned
            /**< The partition order, i.e. # of contexts = 2 ^ \a order. */
            //const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
            IntPtr contents;
            /**< The context's Rice parameters and/or raw bits. */
        }

        public struct FLAC__EntropyCodingMethod
        {
            public FLAC__EntropyCodingMethodType type;
            //union {
            public struct data
            {
                public FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
            }
        }

        public struct FLAC__Subframe_Fixed
        {
            public FLAC__EntropyCodingMethod entropy_coding_method;
            //< The residual coding method.
            public uint order;// unsigned
            //< The polynomial order.
            //FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];//FLAC__MAX_FIXED_ORDER (4u)
            public Int32 warmup0;
            public Int32 warmup1;
            public Int32 warmup2;
            public Int32 warmup3;
            //< Warmup samples to prime the predictor, length == order.
            //const FLAC__int32 *residual;
            public IntPtr residual;
            //< The residual signal, length == (blocksize minus order) samples.
        }

        public struct FLAC__Subframe_LPC
        {
            public FLAC__EntropyCodingMethod entropy_coding_method;
            //< The residual coding method.
            public uint order;// unsigned
            //< The FIR order.
            public uint qlp_coeff_precision;// unsigned
            //< Quantized FIR filter coefficient precision in bits.
            public int quantization_level;
            //< The qlp coeff shift needed.
            //FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];//FLAC__int32
            public Int32 qlp_coeff00, qlp_coeff01, qlp_coeff02, qlp_coeff03, qlp_coeff04, qlp_coeff05, qlp_coeff06, qlp_coeff07, qlp_coeff08, qlp_coeff09,
            qlp_coeff10, qlp_coeff11, qlp_coeff12, qlp_coeff13, qlp_coeff14, qlp_coeff15, qlp_coeff16, qlp_coeff17, qlp_coeff18, qlp_coeff19,
            qlp_coeff20, qlp_coeff21, qlp_coeff22, qlp_coeff23, qlp_coeff24, qlp_coeff25, qlp_coeff26, qlp_coeff27, qlp_coeff28, qlp_coeff29,
            qlp_coeff30, qlp_coeff31;
            //< FIR filter coefficients.
            //FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];//FLAC__int32
            public Int32 warmup00, warmup01, warmup02, warmup03, warmup04, warmup05, warmup06, warmup07, warmup08, warmup09,
            warmup10, warmup11, warmup12, warmup13, warmup14, warmup15, warmup16, warmup17, warmup18, warmup19,
            warmup20, warmup21, warmup22, warmup23, warmup24, warmup25, warmup26, warmup27, warmup28, warmup29,
            warmup30, warmup31;
            //< Warmup samples to prime the predictor, length == order.
            //const FLAC__int32 *residual;
            public IntPtr residual;
            //< The residual signal, length == (blocksize minus order) samples.
        }


        public struct FLAC__Subframe
        {
            public FLAC__SubframeType type;
            //union {
            [StructLayout(LayoutKind.Explicit)]
            public struct _data
            {
                [FieldOffset(0)]
                public FLAC__Subframe_Constant constant;
                [FieldOffset(0)]
                public FLAC__Subframe_Fixed fixed_;
                [FieldOffset(0)]
                public FLAC__Subframe_LPC lpc;
                [FieldOffset(0)]
                public FLAC__Subframe_Verbatim verbatim;
            }
            public _data data;
            public uint wasted_bits;// unsigned
        }

        public struct FLAC__FrameFooter
        {
            public UInt16 crc;//FLAC__uint16 crc;
            //< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of the bytes before the crc, back to and including the frame header sync code.
        }

        public struct FLAC__Frame
        {
            public FLAC__FrameHeader header;
            //FLAC__Subframe subframes[FLAC__MAX_CHANNELS];//FLAC__MAX_CHANNELS (8u)
            public FLAC__Subframe subframes0;
            public FLAC__Subframe subframes1;
            public FLAC__Subframe subframes2;
            public FLAC__Subframe subframes3;
            public FLAC__Subframe subframes4;
            public FLAC__Subframe subframes5;
            public FLAC__Subframe subframes6;
            public FLAC__Subframe subframes7;
            public FLAC__FrameFooter footer;
        }
        public struct FLAC__StreamDecoder
        {
            //struct FLAC__StreamDecoderProtected *protected_; // avoid the C++ keyword 'protected' 
            IntPtr protected_;
            //struct FLAC__StreamDecoderPrivate *private_; // avoid the C++ keyword 'private' 
            IntPtr private_;
        }
        //
        public struct FLAC__StreamMetadata_StreamInfo
        {
            public uint min_blocksize, max_blocksize;// unsigned
            public uint min_framesize, max_framesize;// unsigned
            public uint sample_rate;// unsigned
            public uint channels;// unsigned
            public uint bits_per_sample;// unsigned
            public UInt64 total_samples;// FLAC__uint64
            public byte //FLAC__byte [16]
            md5sum01, md5sum02, md5sum03, md5sum04, md5sum05, md5sum06, md5sum07, md5sum08, md5sum09, md5sum10, md5sum11, md5sum12, md5sum13, md5sum14, md5sum15;
        }

        public struct FLAC__StreamMetadata
        {
            public FLAC__MetadataType type;
            //< The type of the metadata block; used determine which member of the \a data union to dereference.  If type >= FLAC__METADATA_TYPE_UNDEFINED then \a data.unknown must be used. */
            public bool is_last;//FLAC__bool
            /**< \c true if this metadata block is the last, else \a false */
            public uint length;//unsigned
            /**< Length, in bytes, of the block data as it appears in the stream. */
            [StructLayout(LayoutKind.Explicit)]
            public struct _data
            {
                [FieldOffset(0)]
                public FLAC__StreamMetadata_StreamInfo stream_info;
                /*
                [FieldOffset(0)]
                public FLAC__StreamMetadata_Padding padding;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_Application application;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_SeekTable seek_table;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_VorbisComment vorbis_comment;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_CueSheet cue_sheet;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_Picture picture;
                [FieldOffset(0)]
                public FLAC__StreamMetadata_Unknown unknown;
                 */
            };
            public _data data;
            //< Polymorphic block data; use the \a type value to determine which to use. */
        }
        //

        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr FLAC__stream_decoder_new();
        //public static extern FLAC__StreamDecoder FLAC__stream_decoder_new();
        //
        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool FLAC__stream_decoder_set_md5_checking(IntPtr decoder, bool value);
        //FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value);
        //
        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(IntPtr decoder, string file, MulticastDelegate write_callback, MulticastDelegate metadata_callback, MulticastDelegate error_callback, BinaryWriter client_data);
        //FLAC__StreamDecoder *decoder, FILE *file, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data); 

        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern string FLAC__StreamDecoderInitStatusString(int init_status);

        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool FLAC__stream_decoder_process_until_end_of_stream(IntPtr decoder);

        [DllImport("libFLAC.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void FLAC__stream_decoder_delete(IntPtr decoder);

        public static UInt64 total_samples = 0;
        public static uint sample_rate = 0;
        public static uint channels = 0;
        public static uint bps = 0;

        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        public delegate FLAC__StreamDecoderWriteStatus d_write_callback(IntPtr decoder, IntPtr frame, IntPtr buffer, BinaryWriter client_data);
        //
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        public delegate void d_metadata_callback(IntPtr decoder, IntPtr metadata, IntPtr client_data);
        //
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        public delegate void d_error_callback(IntPtr decoder, FLAC__StreamDecoderErrorStatus status, IntPtr client_data);
        //
#pragma warning restore
        // ////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // ////////////////////////////////////////////////////////////////////////////////////////////////////////
        public Handler_Flac()
        {
            staticErrorMessage = "";
        }

        public bool Do(string flacPathName, string outputDirectory, bool forceDecode)
        {
            bool checkMd5 = !forceDecode;
            //
            IntPtr decoder = IntPtr.Zero;
            FLAC__StreamDecoderInitStatus init_status;
            BinaryWriter bw = null;
            //
            FileFlacPathName = flacPathName;
            FileWavPathName = "";
            if (null != outputDirectory)
            {
                FileWavPathName = Path.Combine(Path.GetDirectoryName(outputDirectory), Path.GetFileNameWithoutExtension(flacPathName) + ".wav");
            }
            else
            {
                FileWavPathName = Path.Combine(Path.GetDirectoryName(flacPathName), Path.GetFileNameWithoutExtension(flacPathName) + ".wav");
            }
            //
            //
            try
            {
                bw = new BinaryWriter(new FileStream(FileWavPathName, FileMode.Create, FileAccess.Write, FileShare.Read));
            }
            catch (Exception e)
            {
                ErrorMessage = string.Format("ERROR: opening [{0}] for output {1}", FileWavPathName, e.Message);
                return false;
            }
            //
            //
            try
            {
                //
                if (IntPtr.Zero == (decoder = (IntPtr)FLAC__stream_decoder_new()))
                {
                    ErrorMessage = string.Format("ERROR: allocating decoder");
                    bw.Close();
                    return false;
                }
                //
                FLAC__stream_decoder_set_md5_checking(decoder, checkMd5);
                //
                d_write_callback d_w_c = write_callback;
                d_metadata_callback d_m_c = metadata_callback;
                d_error_callback d_e_c = error_callback;
                //
                init_status = FLAC__stream_decoder_init_file(decoder, FileFlacPathName, d_w_c, d_m_c, d_e_c, /*client_data=*/bw);
                if (init_status != FLAC__StreamDecoderInitStatus.FLAC__STREAM_DECODER_INIT_STATUS_OK)
                {
                    //fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
                    throw new Exception(string.Format("initializing decoder: {0}", init_status));
                }
                else
                {
                    if (!FLAC__stream_decoder_process_until_end_of_stream(decoder))
                    {
                        throw new Exception("decoding FAILED");
                    }
                }

            }
            catch (Exception e)
            {
                ErrorMessage = string.Format("ERROR:1 {0}, {1}", e.Message, e.StackTrace);
                //
                if (null != bw) bw.Close();
                if (File.Exists(FileWavPathName)) File.Delete(FileWavPathName);
                //
                return false;
            }
            finally
            {
                if (IntPtr.Zero != decoder) FLAC__stream_decoder_delete(decoder);
                if (null != bw) bw.Close();
            }
            //
            if ("" != staticErrorMessage)
            {
                ErrorMessage = string.Format("ERROR: {0}",staticErrorMessage);
                return false;
            }
            //
            return true;
        }
        public static FLAC__StreamDecoderWriteStatus write_callback(IntPtr decoder, IntPtr frame, [MarshalAs(UnmanagedType.LPArray)] IntPtr buffer, BinaryWriter bw)
        {
            UInt32 total_size = (UInt32)(total_samples * channels * (bps / 8));

            FLAC__Frame frm = new FLAC__Frame();
            frm = (FLAC__Frame)Marshal.PtrToStructure(frame, typeof(FLAC__Frame));

            if (total_samples == 0)
            {
                staticErrorMessage = string.Format("this example only works for FLAC files that have a total_samples count in STREAMINFO");
                return FLAC__StreamDecoderWriteStatus.FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
            }
            if (channels != 2 || bps != 16)
            {
                staticErrorMessage = string.Format("this example only supports 16bit stereo streams");
                return FLAC__StreamDecoderWriteStatus.FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
            }

            /* write WAVE header before we write the first frame */
            if (frm.header.sample_number == 0)
            {
                //
                try
                {
                    //bw.Write("RIFF");
                    bw.Write(new Byte[] { 0x52, 0x49, 0x46, 0x46 });
                    bw.Write((UInt32)(total_size + 36));
                    //bw.Write("WAVEfmt ");
                    bw.Write(new Byte[] { 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20 });
                    bw.Write((UInt32)(16));
                    bw.Write((UInt16)(1));
                    bw.Write((UInt16)(channels));
                    bw.Write((UInt32)(sample_rate));
                    bw.Write((UInt32)(sample_rate * channels * (bps / 8)));
                    bw.Write((UInt16)(channels * (bps / 8)));
                    bw.Write((UInt16)(bps));
                    //bw.Write("data");
                    bw.Write(new Byte[] { 0x64, 0x61, 0x74, 0x61 });
                    bw.Write((UInt32)(total_size));
                }
                catch (Exception e)
                {
                    staticErrorMessage = string.Format("write error {0}", e.Message);
                    return FLAC__StreamDecoderWriteStatus.FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
                }
                //
            }
            //
            IntPtr pLeft = IntPtr.Zero;
            IntPtr pRight = IntPtr.Zero;
            UInt16 uLeft, uRight;
            /* write decoded PCM samples */
            try
            {
                pLeft = Marshal.ReadIntPtr(buffer, 0);
                pRight = Marshal.ReadIntPtr(buffer, 4);
                for (int i = 0; i < frm.header.blocksize; i++)
                {
                    uLeft = (UInt16)Marshal.ReadInt16(pLeft, i * 4);
                    uRight = (UInt16)Marshal.ReadInt16(pRight, i * 4);
                    bw.Write(uLeft); bw.Write(uRight);
                }
            }
            catch (Exception e)
            {
                staticErrorMessage = string.Format("write error {0}", e.Message);
                return FLAC__StreamDecoderWriteStatus.FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
            }

            return FLAC__StreamDecoderWriteStatus.FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
        }
        public static void metadata_callback(IntPtr decoder, IntPtr metadata, IntPtr client_data)
        {
            FLAC__StreamMetadata sm = new FLAC__StreamMetadata();
            sm = (FLAC__StreamMetadata)Marshal.PtrToStructure(metadata, typeof(FLAC__StreamMetadata));
            /* print some stats */
            if (sm.type == FLAC__MetadataType.FLAC__METADATA_TYPE_STREAMINFO)
            {
                // save for later
                total_samples = sm.data.stream_info.total_samples;
                sample_rate = sm.data.stream_info.sample_rate;
                channels = sm.data.stream_info.channels;
                bps = sm.data.stream_info.bits_per_sample;

                //Console.WriteLine("Sample rate    : {0} Hz", sample_rate);
                //Console.WriteLine("Channels       : {0}", channels);
                //Console.WriteLine("Bits per sample: {0}", bps);
                //Console.WriteLine("Total samples  : {0}", total_samples);
            }
        }
        //
        //void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
        public static void error_callback(IntPtr decoder, FLAC__StreamDecoderErrorStatus status, IntPtr client_data)
        {
            //printf("Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
            staticErrorMessage = string.Format("got error callback: {0}", status);
        }
        // ////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        public bool IsOtputFileOK()
        {
            //
            //
            if (File.Exists(FileFlacPathName))
            {
                int nTicks = -1;
                if (Form1.mi.getPlayTimeForFile(FileFlacPathName, out nTicks))
                {
                    PlayTime = nTicks;
                }
                //
                FileInfo fi = new FileInfo(FileFlacPathName);
                flacFileLength = fi.Length;
            }
            else
            {
                return false;
            }
            //
            //
            if (File.Exists(FileWavPathName))
            {
                FileInfo fi = new FileInfo(FileWavPathName);
                wavFileLength = fi.Length;
                if (0 == wavFileLength) return false;
                if (wavFileLength < flacFileLength) return false;// zbyt krótki
                return true;
            }
            //
            return false;
        }
        //
    }//class
}//namespace
